package com.hulk.ratel.common.util;

import com.google.common.collect.Lists;
import org.dozer.DozerBeanMapper;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 简单封装Dozer, 实现深度转换Bean<->Bean的Mapper.实现:
 * 
 * 1. 持有Mapper的单例. 2. 泛型返回值转换. 3. 批量转换Collection中的所有对象. 4.
 * 区分创建新的B对象与将对象A值复制到已存在的B对象两种函数.
 * 
 * Author: cmt
 */
public class BeanMapper {

	/**
	 * 持有Dozer单例, 避免重复创建DozerMapper消耗资源.
	 */
	private static DozerBeanMapper dozer = new DozerBeanMapper();

	private BeanMapper() {
	}

	/**
	 * 基于Dozer转换对象的类型.
	 */
	public static <T> T map(Object source, Class<T> destinationClass) {
		return dozer.map(source, destinationClass);
	}

	/**
	 * 基于Dozer转换对象的类型.
	 */
	public static <T> T mapNotNull(Object source, Class<T> destinationClass) {
		if (source != null) {
			return dozer.map(source, destinationClass);
		}
		return null;
	}

	/**
	 * 基于Dozer转换Collection中对象的类型.
	 */
	@SuppressWarnings("rawtypes")
	public static <T> List<T> mapList(Collection sourceList,
			Class<T> destinationClass) {
		List<T> destinationList = Lists.newArrayList();
		for (Object sourceObject : sourceList) {
			T destinationObject = dozer.map(sourceObject, destinationClass);
			destinationList.add(destinationObject);

		}
		return destinationList;
	}

	/**
	 * 基于Dozer将对象A的值拷贝到对象B中.
	 */
	public static void copy(Object source, Object destinationObject) {
		dozer.map(source, destinationObject);
	}

	public static void copyNotNull(Object source, Object destinationObject) {
		if (source != null && destinationObject != null) {
			dozer.map(source, destinationObject);
		} else {
			destinationObject = null;
		}
	}



	/**
	 * Map集合对象转化成 JavaBean集合对象
	 *
	 * @param javaBean JavaBean实例对象
	 * @param mapList  Map数据集对象
	 * @return
	 * @author jqlin
	 */
	@SuppressWarnings({"rawtypes"})
	public static <T> List<T> map2Bean(T javaBean, List<Map> mapList) {
		if (mapList == null || mapList.isEmpty()) {
			return null;
		}
		List<T> objectList = new ArrayList<T>();

		T object = null;
		for (Map map : mapList) {
			if (map != null) {
				object = map2Bean(javaBean, map);
				objectList.add(object);
			}
		}

		return objectList;

	}

	/**
	 * Map对象转化成 JavaBean对象
	 *
	 * @param javaBean JavaBean实例对象
	 * @param map      Map对象
	 * @return
	 * @author jqlin
	 */
	@SuppressWarnings({"rawtypes", "unchecked", "hiding"})
	public static <T> T map2Bean(T javaBean, Map map) {
		try {
			// 获取javaBean属性
			BeanInfo beanInfo = Introspector.getBeanInfo(javaBean.getClass());
			// 创建 JavaBean 对象
			Object obj = javaBean.getClass().newInstance();

			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			if (propertyDescriptors != null && propertyDescriptors.length > 0) {
				String propertyName = null; // javaBean属性名
				Object propertyValue = null; // javaBean属性值
				for (PropertyDescriptor pd : propertyDescriptors) {
					propertyName = pd.getName();
					if (map.containsKey(propertyName)) {
						propertyValue = map.get(propertyName);
						pd.getWriteMethod().invoke(obj, new Object[]{propertyValue});
					}
				}
				return (T) obj;
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw  new RuntimeException(e);
		}

		return null;
	}

	/**
	 * JavaBean对象转化成Map对象
	 *
	 * @param javaBean
	 * @return
	 * @author jqlin
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	public static Map bean2Map(Object javaBean,String[] excludeNamesIn) {
		Map map = new HashMap();

		try {
			// 获取javaBean属性
			BeanInfo beanInfo = Introspector.getBeanInfo(javaBean.getClass());

			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			if (propertyDescriptors != null && propertyDescriptors.length > 0) {
				String propertyName = null; // javaBean属性名
				Object propertyValue = null; // javaBean属性值
				for (PropertyDescriptor pd : propertyDescriptors) {
					propertyName = pd.getName();

					if (excludeNamesIn != null) {
						for (String exclude : excludeNamesIn) {
							if (!propertyName.equals(exclude)) {
								Method readMethod = pd.getReadMethod();
								propertyValue = readMethod.invoke(javaBean, new Object[0]);
								map.put(propertyName, propertyValue);
							}
						}
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
			throw  new RuntimeException(e);
		}

		return map;
	}


	/**
	 * 打印对象的值
	 * 
	 * @param obj
	 */
	public static void printBeanValues(Object obj) {
		Class<?> clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			try {
				System.out.println(field.getName() + "=" + field.get(obj));
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

	public static void printBeanValues2(Object obj) {
		Class<?> clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		System.out.println();
		for (Field field : fields) {
			field.setAccessible(true);
			try {
				System.out.print(field.getName() + "=" + field.get(obj) + ", ");
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		System.out.println();
	}

}